package org.fujene.communicate.console;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import org.fujene.communicate.MainService;
import org.fujene.index.IndexingPackage;
import org.fujene.search.SearchPackage;
import org.fujene.search.SearchResult;
import org.fujene.search.SearchResultPackage;

public class Console{
	MainService mains;

	public Console(MainService sys){
		this.mains = sys;
	}

	public void console() throws IOException{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String arg;
		ArrayList<String> history = new ArrayList<String>();

		try{
			Thread.sleep(700);
		}catch(InterruptedException ignored){}

		while(true){
			System.out.print("FARE > ");
			arg = br.readLine();

			String[] args = arg.split(" ");
			if(args.length == 0) continue;
			// take history
			if(args[0].equals("!")){
				if(history.size() == 0){
					System.out.println("No history.");
					continue;
				}
				// last one
				arg = history.get(history.size() - 1);
				args = arg.split(" ");
				System.out.println(arg);
			}else if(args[0].startsWith("!!")){
				// history specified by number
				try{
					int index = Integer.parseInt(args[0].substring(2));
					if(index > history.size()){
						System.out.println("We have " + history.size() + " history.");
						continue;
					}
					arg = history.get(history.size() - index);
					args = arg.split(" ");
					System.out.println(arg);
				}catch(NumberFormatException e){
					System.out.println("Input history index by number.");
					continue;
				}
			}

			if(args[0].equals("index") || args[0].equals("i")){
				if(args.length < 2){
					System.out.printf("Usage: index ");
					System.out.print("(Content) ");
					for(int i = 0; i < mains.contentInfo().contentsNum(); i++)
						System.out.printf("%s ", mains.contentInfo().contentName(i));
					System.out.print("(Appendix) ");
					for(int i = 0; i < mains.contentInfo().appendixNum(); i++)
						System.out.printf("%s ", mains.contentInfo().appendixName(i));
					System.out.print("(Flag - binary) ");
					for(int i = 0; i < mains.contentInfo().binaryFlagNum(); i++)
						System.out.printf("%s ", mains.contentInfo().binaryFlagName(i));
					System.out.print("(Flag - multiple) ");
					for(int i = 0; i < mains.contentInfo().multipleFlagNum(); i++)
						System.out.printf("%s ", mains.contentInfo().multipleFlagName(i));
					System.out.println();
					continue;
				}
				if(args.length < mains.contentInfo().totalNum() + 1){
					System.out.println(String.format("Input appropriate types of contents."));
					continue;
				}
				try{
					IndexingPackage pkg = new IndexingPackage(mains.contentInfo());
					int index = 1;
					for(int i = 0; i < mains.contentInfo().contentsNum(); i++)
						pkg.setContent(args[index + i], i);
					index += mains.contentInfo().contentsNum();
					for(int i = 0; i < mains.contentInfo().appendixNum(); i++)
						pkg.setAppendix(args[index + i], i);
					index += mains.contentInfo().appendixNum();
					for(int i = 0; i < mains.contentInfo().binaryFlagNum(); i++)
						pkg.setBinaryFlag((args[index + i].equalsIgnoreCase("true")? true: false), i);
					index += mains.contentInfo().binaryFlagNum();
					for(int i = 0; i < mains.contentInfo().multipleFlagNum(); i++)
						pkg.setMultipleFlag(Integer.parseInt(args[index + i]), i);
					mains.setNewIndex(pkg);
				}catch(NumberFormatException e){
					System.out.println("Can not input string as ID, in order to number.");
				}
			}else if(args[0].equals("search") || args[0].equals("s")){
				if(args.length < 3){
					System.out.println("Specify query.");
					continue;
				}
				try{
					byte[] searchTypes;
					if(mains.contentInfo().contentsNum() % 8 == 0) searchTypes =
						new byte[mains.contentInfo().contentsNum() / 8];
					else searchTypes = new byte[mains.contentInfo().contentsNum() / 8 + 1];
					int specified, byteIndex, bit;
					boolean notFound = false;
					for(int i = 2; i < args.length; i++){
						specified = mains.contentInfo().contentIndex(args[i]);
//						System.out.println("Specified: " + specified);
						if(specified == -1){
							System.out.printf("Field \"%s\" doesn't exist.%n", args[i]);
							notFound = true;
							break;
						}
						byteIndex = specified / 8;
						bit = specified % 8;
						searchTypes[byteIndex] += (1 << bit);
					}
					if(notFound) continue;
					SearchResultPackage result =
						mains.setNewSearch(SearchPackage.createPackage(args[1], 0, 10, searchTypes, false,
							mains.contentInfo().binaryFlagNum(), mains.contentInfo().multipleFlagNum()));
					if(result == null) continue;
					// Output to stdout if articles has less than 10
					System.out.println("Result: " + result.total() + " articles.");
					for(SearchResult eachResult: result){
						System.out.printf("%d ----- %n", eachResult.index() + 1);
						for(int i = 0; i < eachResult.contentSize(); i++)
							System.out.printf("%s: %s%n", mains.contentInfo().contentName(i),
								eachResult.content(i));
						for(int i = 0; i < eachResult.appendixSize(); i++)
							System.out.printf("%s: %s%n", mains.contentInfo().appendixName(i),
								eachResult.appendix(i));
					}

				}catch(Exception e){
					e.printStackTrace();
				}
			}else if(args[0].equals("searchdetail") || args[0].equals("sp")){
				if(args.length < 5){
					System.out.println("Specify arguments.");
					continue;
				}
				try{
					byte[] searchTypes;
					if(mains.contentInfo().contentsNum() % 8 == 0) searchTypes =
						new byte[mains.contentInfo().contentsNum() / 8];
					else searchTypes = new byte[mains.contentInfo().contentsNum() / 8 + 1];
					int specified, byteIndex, bit;
					for(int i = 4; i < args.length; i++){
						specified = mains.contentInfo().contentIndex(args[i]);
						if(specified == -1){
							System.out.printf("Field \"%s\" doesn't exist.%n", args[i]);
							break;
						}
						byteIndex = specified / 8;
						bit = specified % 8;
						searchTypes[byteIndex] += (1 << bit);
					}
					SearchResultPackage result =
						mains.setNewSearch(SearchPackage.createPackage(args[1], Integer.parseInt(args[2]),
							Integer.parseInt(args[3]), searchTypes, false, mains.contentInfo()
								.binaryFlagNum(), mains.contentInfo().multipleFlagNum()));
					if(result == null) continue;
					// Output to stdout if articles has less than 10
					System.out.println("Result: " + result.total() + " articles.");
					for(SearchResult eachResult: result){
						System.out.printf("%d ----- %n", eachResult.index());
						for(int i = 0; i < eachResult.contentSize(); i++)
							System.out.printf("%s: %s%n", mains.contentInfo().contentName(i),
								eachResult.content(i));
						for(int i = 0; i < eachResult.appendixSize(); i++)
							System.out.printf("%s: %s%n", mains.contentInfo().appendixName(i),
								eachResult.appendix(i));
					}
				}catch(Exception ignored){}
			}else if(args[0].equals("indexcount") || args[0].equals("c")){
				System.out.println("Total count: " + mains.getCounter());
			}else if(args[0].equals("delete") || args[0].equals("d")){
				if(args.length != 2) System.out.println("Specify ID.");
				else mains.setDelete(Long.parseLong(args[1]));
			}else if(args[0].equals("searchcount") || args[0].equals("qc")){
				System.out.println("Total count: " + mains.getSearchcounter());
			}else if(args[0].equals("termcount") || args[0].equals("tc")){
				System.out.println("Term count: " + mains.getTerms());
			}else if(args[0].equals("skipcount") || args[0].equals("sc")){
				System.out.println("Skip ptr. count: " + mains.getSkipPointerLen());
			}else if(args[0].equals("memory") || args[0].equals("m")){
				mains.getMemoryList();
			}else if(args[0].equals("node") || args[0].equals("n")){
				mains.showNodes();
			}else if(args[0].equals("save") || args[0].equals("sv")){
				mains.saveMemory();
			}else if(args[0].equals("read") || args[0].equals("rd")){
				mains.readMemory();
			}else if(args[0].equals("optimize") || args[0].equals("o")){
				mains.optimizeMemory();
			}else if(args[0].equals("processes") || args[0].equals("p")){
				mains.showProcesses();
			}else if(args[0].equals("backup") || args[0].equals("b")){
				mains.backup();
			}else if(args[0].equals("revert") || args[0].equals("r")){
				if(args.length >= 2){
					try{
						long ID = Long.parseLong(args[1]);
						mains.revert(ID);
					}catch(NumberFormatException e){
						System.out.println("Specify by number.");
					}
				}else{
					mains.revert(-1);
				}
			}else if(args[0].equals("backuplist") || args[0].equals("bl")){
				mains.showBackupList();
			}else if(args[0].equals("quit") || args[0].equals("q")){
				mains.suspendMyNode(0);
				mains.setStopper(true);
				break;
			}else{
				System.out.println("Command:");
				System.out.println(" index ID <args ...> [i]: Index content");
				System.out.println(" search <query> type [s]: Search with query");
				System.out.println(" delete ID [d]: Delete content");
				System.out.println(" searchdetail <args> from length [sp]: Search by specified range");
				System.out.println(" indexcount [c]: Count of indexed content");
				System.out.println(" termcount [tc]: Count of indexed terms");
				System.out.println(" searchcount [qc]: Search count");
				System.out.println(" skipcount [sc]: Length of skip counter");
				System.out.println(" optimize [o]: Optimize memory");
				System.out.println(" memory [m]: List of memory block & file in disk");
				System.out.println(" node [n]: List of connected node");
				System.out.println(" processes [p]: Show process queue");
				System.out.println(" backup [b]: Make backup file");
				System.out.println(" revert <ID> [r]: Revert from backup file (specified by ID)");
				System.out.println(" backuplist [bl]: List of backup point");
				System.out.println(" read [rd]: Read files to memory");
				System.out.println(" save [sv]: Save memory to disk");
				System.out.println(" quit [q]: Quit system");
			}
		}
	}
}
